This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.
Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Ctrl+Shift+Enter.
source("./tianfengRwrappers.R")
# plan("multiprocess",workers = 8)
#冠状动脉
human_coronary_countmatrix <- read.csv("GSE131778_human_coronary_scRNAseq.txt", sep = "\t")
func <- function(s) {
paste0(strsplit(s, ".", fixed = T)[[1]][2], "_", strsplit(s, ".", fixed = T)[[1]][1])
}
colnames(human_coronary_countmatrix) <- lapply(colnames(human_coronary_countmatrix), func) # 拆分样本

颈动脉斑块 CA dataset1
# 批量读取计数矩阵
# 需要把行名的gene删掉,用vscode修改
count_mats <- list.files("./CA_GSE155512")
count_mats <- count_mats[count_mats != "sampleinfo.txt"]
allList <- lapply(count_mats, function(folder) {
CreateSeuratObject(
counts = read.csv(paste0("./CA_GSE155512/", folder), sep = "\t"),
project = folder, min.cells = 10, min.features = 300
)
})
# 合并seurat对象
CA_dataset1 <- merge(allList[[1]],
y = allList[-1], add.cell.ids = count_mats,
project = "CA_dataset1"
)
rm(allList)
CA_dataset1 <- PercentageFeatureSet(CA_dataset1, pattern = "^MT-", col.name = "percent.mt") %>%
subset(subset = nFeature_RNA > 600 & nFeature_RNA < 6000 & nCount_RNA > 1000 & nCount_RNA < 30000) %>%
SCTransform(vars.to.regress = "percent.mt", verbose = F) %>%
RunPCA() %>% FindNeighbors(dims = 1:20) %>%
RunUMAP(dims = 1:20) %>%
FindClusters(resolution = 0.1)
颈动脉斑块 CA dataset2
CA_dataset2 <- CreateSeuratObject(Read10X("./CA_GSE159677/"), names.field = 2, names.delim = "-",
project = "CA_dataset2", min.cells = 10, min.features = 300) %>%
PercentageFeatureSet(pattern = "^MT-", col.name = "percent.mt") %>%
subset(subset = nFeature_RNA > 600 & nFeature_RNA < 6000 & nCount_RNA > 1000 & nCount_RNA < 30000) %>%
SCTransform(vars.to.regress = "percent.mt", verbose = F) %>%
RunPCA() %>% FindNeighbors(dims = 1:20) %>%
RunUMAP(dims = 1:20) %>%
FindClusters(resolution = 0.1)
保存结果
saveRDS(human_coronary,"human_coronary.rds")
saveRDS(CA_dataset1,"CA_dataset1.rds")
saveRDS(CA_dataset2,"CA_dataset2.rds") #已经经过分组处理了
读取结果
human_coronary <- readRDS("human_coronary.rds")
CA_dataset1 <- readRDS("CA_dataset1.rds")
修改分群


基质细胞分类

ECs亚群分析 整合
整合算法可能出现负值,运行SCENIC时舍弃了这些异常值
# 提取内皮细胞亚群
ECs_list <- list(subset(CA_dataset1, idents = "Endothelial"), subset(human_coronary, idents = "Endothelial"))
ECs_list <- lapply(X = ECs_list, FUN = function(x) {
x <- NormalizeData(x)
x <- FindVariableFeatures(x, selection.method = "vst", nfeatures = 2000)
})
# 需要分析的差异基因
int_features <- SelectIntegrationFeatures(object.list = ECs_list)
# 选择合并的anchor特征
int_anchors <- FindIntegrationAnchors(object.list = ECs_list, anchor.features = int_features)
# 根据anchor合并
ECs_combined <- IntegrateData(anchorset = int_anchors)
DefaultAssay(ECs_combined) <- "integrated"
rm("ECs_list", "int_features", "int_anchors")
multi_featureplot(c("TNFRSF11B","ACTA2","CNN1","LUM"),human_coronary)

multi_featureplot(c("TNFRSF11B","ACTA2","CNN1","LUM"),CA_dataset1)

multi_featureplot(c("TNFRSF11B","ACTA2","CNN1","LUM"),CA_dataset2)

genes <- c("LGALS3","CD68","KLF4","CLDN5","VWF","ACTA2")
multi_featureplot(genes,CA_dataset2)

Dotplot(genes,CA_dataset2) # 2>5

multi_featureplot(genes,human_coronary)

Dotplot(genes,human_coronary)

cellchat
差异基因

annoation

功能分析
library(org.Hs.eg.db)
GO_dotplot()
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhpcyBpcyBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2suIFdoZW4geW91IGV4ZWN1dGUgY29kZSB3aXRoaW4gdGhlIG5vdGVib29rLCB0aGUgcmVzdWx0cyBhcHBlYXIgYmVuZWF0aCB0aGUgY29kZS4gCgpUcnkgZXhlY3V0aW5nIHRoaXMgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpSdW4qIGJ1dHRvbiB3aXRoaW4gdGhlIGNodW5rIG9yIGJ5IHBsYWNpbmcgeW91ciBjdXJzb3IgaW5zaWRlIGl0IGFuZCBwcmVzc2luZyAqQ3RybCtTaGlmdCtFbnRlciouIAoKYGBge3J9CnNvdXJjZSgiLi90aWFuZmVuZ1J3cmFwcGVycy5SIikKIyBwbGFuKCJtdWx0aXByb2Nlc3MiLHdvcmtlcnMgPSA4KQpgYGAKCiPlhqDnirbliqjohIkKCmBgYHtyfQpodW1hbl9jb3JvbmFyeV9jb3VudG1hdHJpeCA8LSByZWFkLmNzdigiR1NFMTMxNzc4X2h1bWFuX2Nvcm9uYXJ5X3NjUk5Bc2VxLnR4dCIsIHNlcCA9ICJcdCIpCmZ1bmMgPC0gZnVuY3Rpb24ocykgewogIHBhc3RlMChzdHJzcGxpdChzLCAiLiIsIGZpeGVkID0gVClbWzFdXVsyXSwgIl8iLCBzdHJzcGxpdChzLCAiLiIsIGZpeGVkID0gVClbWzFdXVsxXSkKfQpjb2xuYW1lcyhodW1hbl9jb3JvbmFyeV9jb3VudG1hdHJpeCkgPC0gbGFwcGx5KGNvbG5hbWVzKGh1bWFuX2Nvcm9uYXJ5X2NvdW50bWF0cml4KSwgZnVuYykgIyDmi4bliIbmoLfmnKwKYGBgCgpgYGB7cn0KaHVtYW5fY29yb25hcnkgPC0gQ3JlYXRlU2V1cmF0T2JqZWN0KGNvdW50cyA9IGh1bWFuX2Nvcm9uYXJ5X2NvdW50bWF0cml4LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2plY3QgPSAiaHVtYW5fY29yb25hcnkiLCBtaW4uY2VsbHMgPSAxMCwgbWluLmZlYXR1cmVzID0gMzAwKSAlPiUgCiAgICBQZXJjZW50YWdlRmVhdHVyZVNldChwYXR0ZXJuID0gIl5NVC0iLCBjb2wubmFtZSA9ICJwZXJjZW50Lm10IikgJT4lCiAgICBzdWJzZXQoc3Vic2V0ID0gbkZlYXR1cmVfUk5BID4gNjAwICYgbkZlYXR1cmVfUk5BIDwgNjAwMCAmIG5Db3VudF9STkEgPiAxMDAwICYgIG5Db3VudF9STkEgPCAzMDAwMCkgJT4lCiAgICBTQ1RyYW5zZm9ybSh2YXJzLnRvLnJlZ3Jlc3MgPSAicGVyY2VudC5tdCIsIHZlcmJvc2UgPSBGKSAlPiUgCiAgICBSdW5QQ0EoKSAlPiUgRmluZE5laWdoYm9ycyhkaW1zID0gMToyMCkgJT4lIAogICAgUnVuVU1BUChkaW1zID0gMToyMCkgJT4lIAogICAgRmluZENsdXN0ZXJzKHJlc29sdXRpb24gPSAwLjEpCnJtKGh1bWFuX2Nvcm9uYXJ5X2NvdW50bWF0cml4KQpmKCJQTFZBUCIsaHVtYW5fY29yb25hcnkpCmBgYAoKCiMg6aKI5Yqo6ISJ5paR5Z2XIENBIGRhdGFzZXQxCmBgYHtyfQojIOaJuemHj+ivu+WPluiuoeaVsOefqemYtQojIOmcgOimgeaKiuihjOWQjeeahGdlbmXliKDmjonvvIznlKh2c2NvZGXkv67mlLkKY291bnRfbWF0cyA8LSBsaXN0LmZpbGVzKCIuL0NBX0dTRTE1NTUxMiIpCmNvdW50X21hdHMgPC0gY291bnRfbWF0c1tjb3VudF9tYXRzICE9ICJzYW1wbGVpbmZvLnR4dCJdCmFsbExpc3QgPC0gbGFwcGx5KGNvdW50X21hdHMsIGZ1bmN0aW9uKGZvbGRlcikgewogIENyZWF0ZVNldXJhdE9iamVjdCgKICAgIGNvdW50cyA9IHJlYWQuY3N2KHBhc3RlMCgiLi9DQV9HU0UxNTU1MTIvIiwgZm9sZGVyKSwgc2VwID0gIlx0IiksCiAgICBwcm9qZWN0ID0gZm9sZGVyLCBtaW4uY2VsbHMgPSAxMCwgbWluLmZlYXR1cmVzID0gMzAwCiAgKQp9KQojIOWQiOW5tnNldXJhdOWvueixoQpDQV9kYXRhc2V0MSA8LSBtZXJnZShhbGxMaXN0W1sxXV0sCiAgeSA9IGFsbExpc3RbLTFdLCBhZGQuY2VsbC5pZHMgPSBjb3VudF9tYXRzLAogIHByb2plY3QgPSAiQ0FfZGF0YXNldDEiCikKcm0oYWxsTGlzdCkKCkNBX2RhdGFzZXQxIDwtIFBlcmNlbnRhZ2VGZWF0dXJlU2V0KENBX2RhdGFzZXQxLCBwYXR0ZXJuID0gIl5NVC0iLCBjb2wubmFtZSA9ICJwZXJjZW50Lm10IikgJT4lCiAgICBzdWJzZXQoc3Vic2V0ID0gbkZlYXR1cmVfUk5BID4gNjAwICYgbkZlYXR1cmVfUk5BIDwgNjAwMCAmIG5Db3VudF9STkEgPiAxMDAwICYgIG5Db3VudF9STkEgPCAzMDAwMCkgJT4lCiAgICBTQ1RyYW5zZm9ybSh2YXJzLnRvLnJlZ3Jlc3MgPSAicGVyY2VudC5tdCIsIHZlcmJvc2UgPSBGKSAlPiUgCiAgICBSdW5QQ0EoKSAlPiUgRmluZE5laWdoYm9ycyhkaW1zID0gMToyMCkgJT4lIAogICAgUnVuVU1BUChkaW1zID0gMToyMCkgJT4lIAogICAgRmluZENsdXN0ZXJzKHJlc29sdXRpb24gPSAwLjEpCgpgYGAKCgojIOmiiOWKqOiEieaWkeWdlyBDQSBkYXRhc2V0MgpgYGB7cn0KQ0FfZGF0YXNldDIgPC0gQ3JlYXRlU2V1cmF0T2JqZWN0KFJlYWQxMFgoIi4vQ0FfR1NFMTU5Njc3LyIpLCBuYW1lcy5maWVsZCA9IDIsIG5hbWVzLmRlbGltID0gIi0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2plY3QgPSAiQ0FfZGF0YXNldDIiLCBtaW4uY2VsbHMgPSAxMCwgbWluLmZlYXR1cmVzID0gMzAwKSAlPiUgCiAgUGVyY2VudGFnZUZlYXR1cmVTZXQocGF0dGVybiA9ICJeTVQtIiwgY29sLm5hbWUgPSAicGVyY2VudC5tdCIpICU+JQogIHN1YnNldChzdWJzZXQgPSBuRmVhdHVyZV9STkEgPiA2MDAgJiBuRmVhdHVyZV9STkEgPCA2MDAwICYgbkNvdW50X1JOQSA+IDEwMDAgJiAgbkNvdW50X1JOQSA8IDMwMDAwKSAlPiUKICBTQ1RyYW5zZm9ybSh2YXJzLnRvLnJlZ3Jlc3MgPSAicGVyY2VudC5tdCIsIHZlcmJvc2UgPSBGKSAlPiUgCiAgUnVuUENBKCkgJT4lIEZpbmROZWlnaGJvcnMoZGltcyA9IDE6MjApICU+JSAKICBSdW5VTUFQKGRpbXMgPSAxOjIwKSAlPiUgCiAgRmluZENsdXN0ZXJzKHJlc29sdXRpb24gPSAwLjEpCmBgYAoKCiMg5re75YqgbWV0YWRhdGEgc2FtcGxlc+WtmOWCqOWujOaVtOS/oeaBr++8jGNvbmRpdGlvbnPmjInljLrln5/liIbvvIxncm91cHPmjInnl4XkvovliIYKYGBge3J9CklkZW50cyhodW1hbl9jb3JvbmFyeSkgPC0gaHVtYW5fY29yb25hcnkkb3JpZy5pZGVudApJZGVudHMoaHVtYW5fY29yb25hcnkpIDwtIGMoIjEiLCIxIiwiMiIsIjIiLCIzIiwiMyIsIjQiLCI0IikKaHVtYW5fY29yb25hcnkkc2FtcGxlcyA8LSBJZGVudHMoaHVtYW5fY29yb25hcnkpCklkZW50cyhodW1hbl9jb3JvbmFyeSkgPC0gaHVtYW5fY29yb25hcnkkc2V1cmF0X2NsdXN0ZXJzCgpJZGVudHMoQ0FfZGF0YXNldDIpIDwtIENBX2RhdGFzZXQyJG9yaWcuaWRlbnQKQ0FfZGF0YXNldDIgPC0gUmVuYW1lSWRlbnRzKENBX2RhdGFzZXQyLCcxJyA9ICdBQ18xJywnMicgPSAnUEFfMScsJzMnID0gJ0FDXzInLCc0JyA9ICdQQV8yJywnNScgPSAnQUNfMycsJzYnID0gJ1BBXzMnKQpVTUFQUGxvdChDQV9kYXRhc2V0MikKCkNBX2RhdGFzZXQyJHNhbXBsZSA8LSBJZGVudHMoQ0FfZGF0YXNldDIpCkNBX2RhdGFzZXQyIDwtIFJlbmFtZUlkZW50cyhDQV9kYXRhc2V0MiwnQUNfMScgPSAnQUMnLCdQQV8xJyA9ICdQQScsJ0FDXzInPSAnQUMnLCdQQV8yJz0gJ1BBJywnQUNfMyc9ICdBQycsJ1BBXzMnPSAnUEEnKQpDQV9kYXRhc2V0MiRjb25kaXRpb25zIDwtIElkZW50cyhDQV9kYXRhc2V0MikKSWRlbnRzKENBX2RhdGFzZXQyKSA8LSBDQV9kYXRhc2V0MiRvcmlnLmlkZW50CkNBX2RhdGFzZXQyIDwtIFJlbmFtZUlkZW50cyhDQV9kYXRhc2V0MiwgJzEnID0gJ3NwXzEnLCcyJyA9ICdzcF8xJywnMycgPSAnc3BfMicsJzQnID0gJ3NwXzInLCc1JyA9ICdzcF8zJywnNicgPSAnc3BfMycpCkNBX2RhdGFzZXQyJGdyb3VwcyA8LSBJZGVudHMoQ0FfZGF0YXNldDIpCklkZW50cyhDQV9kYXRhc2V0MikgPC0gQ0FfZGF0YXNldDIkc2V1cmF0X2NsdXN0ZXJzCmBgYAoKIyDkv53lrZjnu5PmnpwKYGBge3J9CnNhdmVSRFMoaHVtYW5fY29yb25hcnksImh1bWFuX2Nvcm9uYXJ5LnJkcyIpCnNhdmVSRFMoQ0FfZGF0YXNldDEsIkNBX2RhdGFzZXQxLnJkcyIpCnNhdmVSRFMoQ0FfZGF0YXNldDIsIkNBX2RhdGFzZXQyLnJkcyIpICPlt7Lnu4/nu4/ov4fliIbnu4TlpITnkIbkuoYKYGBgCgotLS0tCiMg6K+75Y+W57uT5p6cCmBgYHtyfQpodW1hbl9jb3JvbmFyeSA8LSByZWFkUkRTKCJodW1hbl9jb3JvbmFyeS5yZHMiKQpDQV9kYXRhc2V0MSA8LSByZWFkUkRTKCJDQV9kYXRhc2V0MS5yZHMiKQpDQV9kYXRhc2V0MiA8LSByZWFkUkRTKCJDQV9kYXRhc2V0Mi5yZHMiKSAj5bey57uP57uP6L+H5YiG57uE5aSE55CG5LqGCmBgYAoKIyMg5L+u5pS55YiG576kCmBgYHtyfQp1bWFwcGxvdChDQV9kYXRhc2V0Miwgc3BsaXQuYnkgPSAic2FtcGxlIikKdW1hcHBsb3QoQ0FfZGF0YXNldDIsZ3JvdXAuYnkgPSAiZ3JvdXBzIiwgc3BsaXQuYnkgPSAiY29uZGl0aW9ucyIpCm11bHRpX2ZlYXR1cmVwbG90KGMoIkhFWTEiLCJHSkE1IiwiU0VNQTNHIiwiQ1hDTDEyIiwiU09YMTciLCJDREg1IiwiUEVDQU0xIiksQ0FfZGF0YXNldDIpCm11bHRpX2ZlYXR1cmVwbG90KGMoIkFDS1IxIiwiUExWQVAiLCJJVEdBNiIsIlBFQ0FNMSIpLENBX2RhdGFzZXQyKQpgYGAKYGBge3J9CiMgdGFibGUoQ0FfZGF0YXNldDIkc2FtcGxlKQoKIyDlhbPms6hjbHVzdGVyIDMtNiBFQwojIGNsdXN0ZXIgNyDln7rotKjnu4bog54KCm11bHRpX2ZlYXR1cmVwbG90KGMoIkxZWiIsIlBUUFJDIiwiQ0Q2OSIsIkVQQ0FNIiwiQ0RIMSIsIlBER0ZSQiIsIkNPTDFBMiIsIlBFQ0FNMSIsIkNMRE41IiksQ0FfZGF0YXNldDIpCgpEb3RwbG90KGMoIkxVTSIsIk1NUDIiLCJNR1AiLCJEQ04iLCJNWUgxMSIsIkFDVEEyIiwiQ05OMSIsIlRBR0xOIiksQ0FfZGF0YXNldDIpICNjbHVzdGVyIDcg57uG6IOe5Y+v5Lul6KKr6K6k5Li65pivbW9kdWxhdGVkIFNNQ3MKQ0FfZGF0YXNldDIgPC0gQWRkTW9kdWxlU2NvcmUoQ0FfZGF0YXNldDIsbGlzdChjKCJMVU0iLCJNTVAyIiwiTUdQIiwiRENOIikpKQpDQV9kYXRhc2V0MiA8LSBBZGRNb2R1bGVTY29yZShDQV9kYXRhc2V0MixsaXN0KGMoIk1ZSDExIiwiQUNUQTIiLCJDTk4xIiwiVEFHTE4iKSkpCm11bHRpX2ZlYXR1cmVwbG90KGMoIkNsdXN0ZXIxIiwiTFVNIiwiQUNUQTIiLCJUQUdMTiIpLENBX2RhdGFzZXQyKQptdWx0aV9mZWF0dXJlcGxvdChjKCJNTVAyIiwiR0pBNCIsIlBFQ0FNMSIsIkFDS1IxIiksIENBX2RhdGFzZXQyKQptdWx0aV9mZWF0dXJlcGxvdChjKCJNTVAyIiwiR0pBNCIsIlBFQ0FNMSIsIkFDS1IxIiksIGh1bWFuX2Nvcm9uYXJ5KQoKYGBgCiMg5Z+66LSo57uG6IOe5YiG57G7CmBgYHtyfQptdWx0aV9mZWF0dXJlcGxvdChjKCJMWVoiLCJQVFBSQyIsIkNENjkiLCJQREdGUkIiLCJDT0wxQTIiLCJQRUNBTTEiLCJDTERONSIpLCBDQV9kYXRhc2V0MikKIyBtdWx0aV9mZWF0dXJlcGxvdChjKCJBQ1RBMiIsIkZOMSIpLCBDQV9kYXRhc2V0MikKdW1hcHBsb3QoQ0FfZGF0YXNldDIpCmx5bV9kczIgPC0gc3Vic2V0KENBX2RhdGFzZXQyLCBpZGVudHMgPSBjKCcwJywnNCcsJzknKSkgICNodW1hbl9jb3Ig6YCJ5oupMCAzIDQgIENBX2RhdGFzZXQxIOmAieaLqTDvvIw05L2c5Li65Z+66LSo57uG6IOeIENBX2RhdGFzZXQyIOmAieaLqTflkowy5L2c5Li65Z+66LSo57uG6IOeIG15ZWxvaWQgQ0FfZGF0YXNldDIgMQojQ0FfZGF0YXNldDIg6YCJ5oupN+WSjDLkvZzkuLrln7rotKjnu4bog54KdW1hcHBsb3QobHltX2RzMixzcGxpdC5ieSA9ICJzYW1wbGUiKSMg5reL5be0CnNhdmVSRFMobHltX2RzMiwibHltX2RzMi5yZHMiKQoKIyBzYXZlUkRTKGRzMCwiZHMwLnJkcyIpCiMgc2F2ZVJEUyhkczEsImRzMS5yZHMiKQoKYGBgCgoKCiMgRUNz5Lqa576k5YiG5p6QIOaVtOWQiAojIyDmlbTlkIjnrpfms5Xlj6/og73lh7rnjrDotJ/lgLzvvIzov5DooYxTQ0VOSUPml7boiI3lvIPkuobov5nkupvlvILluLjlgLwKYGBge3J9CiMg5o+Q5Y+W5YaF55qu57uG6IOe5Lqa576kCkVDc19saXN0IDwtIGxpc3Qoc3Vic2V0KENBX2RhdGFzZXQxLCBpZGVudHMgPSAiRW5kb3RoZWxpYWwiKSwgc3Vic2V0KGh1bWFuX2Nvcm9uYXJ5LCBpZGVudHMgPSAiRW5kb3RoZWxpYWwiKSkKCkVDc19saXN0IDwtIGxhcHBseShYID0gRUNzX2xpc3QsIEZVTiA9IGZ1bmN0aW9uKHgpIHsKICB4IDwtIE5vcm1hbGl6ZURhdGEoeCkKICB4IDwtIEZpbmRWYXJpYWJsZUZlYXR1cmVzKHgsIHNlbGVjdGlvbi5tZXRob2QgPSAidnN0IiwgbmZlYXR1cmVzID0gMjAwMCkKfSkKIyDpnIDopoHliIbmnpDnmoTlt67lvILln7rlm6AKaW50X2ZlYXR1cmVzIDwtIFNlbGVjdEludGVncmF0aW9uRmVhdHVyZXMob2JqZWN0Lmxpc3QgPSBFQ3NfbGlzdCkKIyDpgInmi6nlkIjlubbnmoRhbmNob3LnibnlvoEKaW50X2FuY2hvcnMgPC0gRmluZEludGVncmF0aW9uQW5jaG9ycyhvYmplY3QubGlzdCA9IEVDc19saXN0LCBhbmNob3IuZmVhdHVyZXMgPSBpbnRfZmVhdHVyZXMpCgojIOagueaNrmFuY2hvcuWQiOW5tgpFQ3NfY29tYmluZWQgPC0gSW50ZWdyYXRlRGF0YShhbmNob3JzZXQgPSBpbnRfYW5jaG9ycykKCkRlZmF1bHRBc3NheShFQ3NfY29tYmluZWQpIDwtICJpbnRlZ3JhdGVkIgpybSgiRUNzX2xpc3QiLCAiaW50X2ZlYXR1cmVzIiwgImludF9hbmNob3JzIikKYGBgCgoKYGBge3J9Cm11bHRpX2ZlYXR1cmVwbG90KGMoIlRORlJTRjExQiIsIkFDVEEyIiwiQ05OMSIsIkxVTSIpLGh1bWFuX2Nvcm9uYXJ5KQptdWx0aV9mZWF0dXJlcGxvdChjKCJUTkZSU0YxMUIiLCJBQ1RBMiIsIkNOTjEiLCJMVU0iKSxDQV9kYXRhc2V0MSkKbXVsdGlfZmVhdHVyZXBsb3QoYygiVE5GUlNGMTFCIiwiQUNUQTIiLCJDTk4xIiwiTFVNIiksQ0FfZGF0YXNldDIpCmBgYAoKYGBge3J9CmdlbmVzIDwtIGMoIkxHQUxTMyIsIkNENjgiLCJLTEY0IiwiQ0xETjUiLCJWV0YiLCJBQ1RBMiIpCm11bHRpX2ZlYXR1cmVwbG90KGdlbmVzLENBX2RhdGFzZXQyKQpEb3RwbG90KGdlbmVzLENBX2RhdGFzZXQyKSAjIDI+NQptdWx0aV9mZWF0dXJlcGxvdChnZW5lcyxodW1hbl9jb3JvbmFyeSkKRG90cGxvdChnZW5lcyxodW1hbl9jb3JvbmFyeSkKYGBgCiMgY2VsbGNoYXQKYGBge3J9CgpgYGAKCgojIOW3ruW8guWfuuWboApgYGB7cn0KdW1hcHBsb3QoZHMyLHNwbGl0LmJ5ID0gImNvbmRpdGlvbnMiKQpkczIgPC0gZHMyICU+JSBGaW5kTmVpZ2hib3JzKGRpbXMgPSAxOjIwKSAlPiUgRmluZENsdXN0ZXJzKHJlc29sdXRpb24gPSAwLjEpCnVtYXBwbG90KGRzMiwgZ3JvdXAuYnkgPSAic2V1cmF0X2NsdXN0ZXJzIixzcGxpdC5ieSA9ICJjb25kaXRpb25zIikKSWRlbnRzKGRzMikgPC0gZHMyJGNvbmRpdGlvbnMKZHMyX0FDIDwtIHN1YnNldChkczIsIGlkZW50cyA9ICJBQyIpCmRzMl9QQSA8LSBzdWJzZXQoZHMyLCBpZGVudHMgPSAiUEEiKQpkczJfQUMgPC0gZHMyX0FDICU+JSBGaW5kTmVpZ2hib3JzKGRpbXMgPSAxOjIwKSAlPiUgRmluZENsdXN0ZXJzKHJlc29sdXRpb24gPSAwLjEpCmRzMl9QQSA8LSBkczJfUEEgJT4lIEZpbmROZWlnaGJvcnMoZGltcyA9IDE6MjApICU+JSBGaW5kQ2x1c3RlcnMocmVzb2x1dGlvbiA9IDAuMSkKCnVtYXBwbG90KGRzMl9BQykgKyBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtNSwxNSksYnJlYWtzID0gTlVMTCkgKwogICAgICAgIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKC01LDE1KSxicmVha3MgPSBOVUxMKQp1bWFwcGxvdChkczJfUEEpKyBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtNSwxNSksYnJlYWtzID0gTlVMTCkgKwogICAgICAgIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKC01LDE1KSxicmVha3MgPSBOVUxMKQoKZHMyX21hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMoZHMyLCBsb2dmYy50aHJlc2hvbGQgPSAwLjUsIG1pbi5kaWZmLnBjdCA9IDAuMykKCm11bHRpX2ZlYXR1cmVwbG90KGMoIkRDTiIsIlZDQU0xIiwiTFVNIiwiQ05OMSIsIkFDVEEyIiwiR0pBNCIsIk9NRCIsIgkKRkJMTjEiLCJDWENMMTQiLCJDMyIpLGRzMikKCkRvdHBsb3QoYygiRENOIiwiVkNBTTEiLCJMVU0iLCJDTk4xIiwiQUNUQTIiLCJHSkE0IiwiT01EIiwiRkJMTjEiLCJDWENMMTQiLCJDMyIpLGRzMikKYGBgCiMjIGFubm9hdGlvbgpgYGB7cn0KbXVsdGlfZmVhdHVyZXBsb3QoYygiTFlaIiwiUFRQUkMiLCJDRDY5IiwiUERHRlJCIiwiQ09MMUEyIiwiUEVDQU0xIiwiQ0xETjUiKSwgQ0FfZGF0YXNldDIpCmYoIkFDVEEyIiwgQ0FfZGF0YXNldDEpCmBgYAoKCiMg5Yqf6IO95YiG5p6QCmBgYHtyfQpsaWJyYXJ5KG9yZy5Icy5lZy5kYikKR09fZG90cGxvdCgpCmBgYAoK